/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 *
 * $Id: TextClient.hpp,v 1.7 2009-12-08 10:48:28 morsko Exp $
 *
 * \file
 * \brief MaCI - Text Interface Client header
 * \author Matthieu Myrsky <matthieu.myrsky@tkk.fi>
 *
 * \todo 
 */
#ifndef _MACI_INTERFACE_TEXTCLIENT_HPP_
#define _MACI_INTERFACE_TEXTCLIENT_HPP_

#include "MaCI.hpp"
#include "TextData.hpp"
#include "thread.hpp"
#include "sync.hpp"
#include <map>



namespace MaCI {
  namespace Text {
    // Forward declarations.
    class CTextData;
    class CTextClient;

    enum EArrivedDataType{
      KTypeTextFromServer = 0,
      KTypeTextReplyFromServer = 1
    };

    /** Callback interface class for Text interface.
     *
     * This interface defines functions which can be used for
     * TextClient callbacks. These functions are executed (more
     * detail per function basis) as new data arrives, and directly
     * from the context of the receiving thread. <b>Therefore, it is
     * important that the handling function is as simple and fast as
     * possible, as it will block the execution of the receiving
     * thread while executed.</b>
     */
    class CTextClientCallback
    {
    public:

      CTextClientCallback() {}
      virtual ~CTextClientCallback() {}


      /** Handler function for Text data from server
       *
       * This function is called when the TextClient receives new
       * text-data from the server.
       *
       * \note <b>Keep this function simple & fast as it will block the 
       * data receiving thread while executing!</b>
       *
       * @param[in] aText       Constant reference std::string 
       *                        containing the received event.
       * @param[in] aDataSequence Sequence number of the received data. 
       *                        This should increment by one on each call.
       * @param[in] aTextClient Reference to TextClient 
       *                        instance which received this event.
       */
      virtual void OnTextFromServer(std::string &aText, 
                                    const unsigned int aDataSequence,
                                    CTextClient &aTextClient) = 0;

      /** Handler function for Text reply data from server
       *
       * This function is called when the TextClient receives new
       * reply text-data from the server.
       *
       * \note <b>Keep this function simple & fast as it will block the 
       * data receiving thread while executing!</b>
       *
       * @param[in] aText         Constant reference to std::string 
       *                          containing the received event.
       * @param[in] aDataSequence Sequence number of the received data. 
       *                          This should increment by one on each call.
       * @param[in] aTextClient   Reference to TextClient 
       *                          instance which received this event.
       */
      virtual void OnTextReplyFromServer(std::string &aText, 
                                         const unsigned int aDataSequence,
                                         CTextClient &aTextClient) = 0;
    };

    

    class CTextClient : private gim::CSync,
                        private gim::CThread,
                        public MaCI::CMaCI
    {
    public:

      /** Constructor.
       * 
       * Constructor of the TextClient. This requires;
       * a pointer to Initialized and connected GIMI, minor
       * number of this interface (Used as GIMI minor number)
       *
       * @param[in] aGIMIPtr Pointer to GIMI used for communication
       * @param[in] aInterfaceMinor Interface minor number. Usually
       *            used to indicate the instance of devices of same
       *            type.
       */     
      CTextClient(gimi::GIMI *aGIMIPtr, const int aInterfaceMinor);

      
      /** Destructor.
       */
      ~CTextClient();
      

      /** Open client interface.
       */
      EMaCIError DoOpen(void);


      /** Close client interface.
       */
      EMaCIError DoClose(void);

      /**
       * /deprecated Use SendText(std::string &aText) instead
       * Sends wanted text string to server
       *
       * @param[in] aText             Text to send
       * @param[in] aTimeout_ms       Timeout in milliseconds to sleep waiting
       *                              for the operation to complete
       * @return                      True if succeeded, false if failed(timeout, no connection..)
       */
      bool SendText(const std::string &aText, unsigned int aTimeout_ms) __attribute__((deprecated));

      /**
       * Sends wanted text string to server
       *
       * @param[in] aText             Text to send
       * @return                      True if succeeded, false if failed(timeout, no connection..)
       */
      bool SendText(const std::string &aText);

     
      /**
       * Clear all messages from Server
       *
       * @return                      True if succeeded, false if failed(timeout, no connection..)
       */
      bool ClearText(void);

      /**
       * Get event when server have accomplished text that you have sent.
       *
       * @param[out] aText            Reference to text string where the text is saved
       * @param[in]  aSeq             Block until greater sequence number
       *                              available.
       *                              Initially, set the pointed data to 0.
       *                              After that, don't touch the value,
       *                              but pass it on on each call. 
       * @param[in] aTimeout_ms       Timeout int ms. The function block until 
       *                              greater sequence number is available or 
       *                              timeout reached.
       * @return                      True; on success (data stored)
       *                              False; on failure (no data stored
       *                              or partial)
       *
       */
      bool GetTextAccomplishedEvent(std::string &aText,
                                    int *aSeq,
                                    unsigned int aTimeout_ms);


      /**
       * Gets text event from server
       * 
       * @param aText                 Reference to text string where the text is saved
       * @param[in]  aSeq             Block until greater sequence number
       *                              available.
       *                              Initially, set the pointed data to 0.
       *                              After that, don't touch the value,
       *                              but pass it on on each call. 
       * @param[in] aTimeout_ms       Timeout int ms. The function block until 
       *                              greater sequence number is available or 
       *                              timeout reached.
       * @return                      True; on success (data stored)
       *                              False; on failure (no data stored
       *                              or partial)
       *
       */
      bool GetTextEvent(std::string &aText,
                        int *aSeq,
                        unsigned int aTimeout_ms);

      /** Assigns the Text client callback function. 
       *
       * This sets a function object for calling a text client
       * callback. If this is set, the interface calls the assigned
       * functions immediately when event is available.
       * 
       * \note As the function is run in the context of the receiving
       * thread, user must make sure that the callback function is
       * fast. As if the function executes too long, receiving events
       * is interrupted.
       *
       * @param[in] aTextClientCallback Pointer to class implementing the interface
       *                                CTextClientCallback.
       */
      void SetTextClientCallback(CTextClientCallback *aTextClientCallback) {
        iTextClientCallback = aTextClientCallback;
      }

 private:
      /// Thread runner function. Is in charge of receiving events.
      int ThreadFunction(const int aThreadNumber);

      int ProcessMessage(const gimi::GIMIMessage &msg); ///< Incoming data processor function
      CTextData iLastTextSaid;
      CTextData iLastTextFromServer;
      int iLastTextReplySeq;	  
      int iTextFromServerSeq;
      CTextClientCallback *iTextClientCallback;
      CTextClient(const CTextClient &)
        : CSync(2,1), 
          CThread(1),
          CMaCI(NULL, GIMI_PROTOCOL_MACI_TEXT, 0,""),
          iLastTextSaid(),
          iLastTextFromServer(),
          iLastTextReplySeq(0),
          iTextFromServerSeq(0),
          iTextClientCallback(NULL){}
        
      CTextClient &operator=(const CTextClient &) { return *this; }
    };
  }
}
#endif  ///<_MACI_INTERFACE_TEXTCLIENT_HPP_
